package com.struts.core.util;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.struts.core.annotation.Control;
import com.struts.core.annotation.Repository;
import com.struts.core.annotation.ReqMapping;
import com.struts.core.annotation.Resource;
import com.struts.core.annotation.Service;

/**
 * 解析Struts配置文件
 * 
 * @author gzq
 *
 */
public class LoadStrutsConfigUtil {

	/**
	 * 通过配置文件和注解装载一个Map对象，并返回 key值为请求的url，例如/userAction/add.do
	 * value值为对应的Action（Control）类+"||"+方法+"||"+方法参数
	 * 例如com.struts.business.UserAction||add||com.struts.business.UserForm
	 * 
	 * @param path
	 * @return
	 */
	public static Map<String, Object> LoadStrutsConfig(String path) {
		SAXReader reader = new SAXReader();
		Map<String, Object> map = new HashMap<String, Object>();
		try {
			Document doc = reader.read(new File(path));
			Element root = doc.getRootElement();
			// 扫描注解
			map.putAll(scanPackage(root));
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		return map;
	}

	/**
	 * 扫描包文件的类
	 * 
	 * @param root
	 * @return
	 */
	private static Map<String, Object> scanPackage(Element root) {
		// 获取所有包
		String[] packages = getPackage(root);
		// 获取包里所有类
		@SuppressWarnings("rawtypes")
		List<Class> classes = getClasses(packages);
		// 解析类的注解
		return parseClass(classes);
	}

	/**
	 * 获取配置文件里需要扫描的jar包
	 * 
	 * @param root
	 * @return
	 */
	private static String[] getPackage(Element root) {
		Element e = root.element("scan");
		if (e == null) {
			return null;
		}
		String[] packages = e.attributeValue("package").split(",");
		return packages;
	}

	/**
	 * 获取包里所有类文件
	 * 
	 * @param packages
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	private static List<Class> getClasses(String[] packages) {
		List<Class> list = new ArrayList<Class>();
		String classpath = Thread.currentThread().getContextClassLoader()
				.getResource("").getPath();
		for (String pack : packages) {
			File file = new File(classpath + pack.replace(".", "/"));
			File[] files = file.listFiles();
			for (File f : files) {
				if (!f.isDirectory()) {
					try {
						String fname = f.getName().substring(0,
								f.getName().lastIndexOf("."));
						list.add(Class.forName(pack + "." + fname));
					} catch (ClassNotFoundException e) {
						e.printStackTrace();
					}
				}
			}
		}
		return list;
	}

	/**
	 * 添加service层和dao层注解
	 * 
	 * @param list
	 * @param map
	 * @param ServiceStrList
	 * @param fieldList
	 */
	@SuppressWarnings({ "rawtypes", "unused", "unchecked" })
	private static void serviceAndDaoClass(List<Class> list,
			Map<String, Object> map, List<String> ServiceStrList,
			List<String> fieldList) {
		// 保存service层的注解属性
		List<String> DaoStrList = new ArrayList<String>();
		List<String> serviceFieldList = new ArrayList<String>();

		for (Class clazz : list) {
			Service service = (Service) clazz.getAnnotation(Service.class);
			Repository repository = (Repository) clazz
					.getAnnotation(Repository.class);
			if (service != null) {
				ServiceStrList.add(clazz.getName());
			}
			if (repository != null) {
				DaoStrList.add(clazz.getName());
			}

		}

		for (Class clazz : list) {
			Service service = (Service) clazz.getAnnotation(Service.class);
			if (service != null) {
				// 保存service层的注解属性
				Field[] files = clazz.getDeclaredFields();
				for (Field field : files) {
					Resource res = field.getAnnotation(Resource.class);
					if (res != null) {
						String fieldName = field.getName();
						for (String daoFieldName : DaoStrList) {
							String getClass = StringUtil
									.getClassName(daoFieldName);
							if (fieldName.equalsIgnoreCase(getClass)) {
								fieldList.add(fieldName);
								map.put(clazz.getName() + fieldName,
										daoFieldName);
							}

						}

					}

				}

			}
		}

	}

	/**
	 * 解析类文件的注解
	 * 
	 * @param list
	 * @return
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private static Map<String, Object> parseClass(List<Class> list) {
		Map<String, Object> map = new HashMap<String, Object>();
		// 保存Control层的注解属性
		List<String> ServiceStrList = new ArrayList<String>();
		List<String> fieldList = new ArrayList<String>();
		// 添加service层和dao层注解
		serviceAndDaoClass(list, map, ServiceStrList, fieldList);

		for (Class clazz : list) {
			// Action（Control）类名
			Control cont = (Control) clazz.getAnnotation(Control.class);

			if (cont != null) {
				// Action（Control）类的ReqMapping注解
				ReqMapping req_class = (ReqMapping) clazz
						.getAnnotation(ReqMapping.class);
				Method[] methods = clazz.getMethods();

				// 保存Control层的注解属性
				Field[] files = clazz.getDeclaredFields();
				for (Field field : files) {
					Resource res = field.getAnnotation(Resource.class);
					if (res != null) {
						String fieldName = field.getName();
						for (String classFieldName : ServiceStrList) {
							String getClass = StringUtil
									.getClassName(classFieldName);
							if (fieldName.equalsIgnoreCase(getClass)) {
								fieldList.add(fieldName);
								map.put(clazz.getName() + fieldName,
										classFieldName);
							}

						}

					}

				}
				// 保存Control层的注解属性-结束

				for (Method m : methods) {
					// 方法的ReqMapping注解
					ReqMapping req = m.getAnnotation(ReqMapping.class);
					if (req != null) {
						StringBuffer paraNames = new StringBuffer();
						for (Class para : m.getParameterTypes()) {
							// 方法的参数
							paraNames.append("," + para.getName());
						}
						String url = req.value();
						// 装载map key=类url+方法url+webxml的urlPattern
						// value = 类名||方法名||参数
						map.put(req_class.value() + url + getUrlPattern(null),
								clazz.getName() + "||" + m.getName() + "||"
										+ paraNames.substring(1));
					}
				}

			}

		}
		return map;
	}

	/**
	 * 获取servlet对应的urlPattern值
	 * 
	 * @param servletName
	 * @return
	 */
	private static String getUrlPattern(String servletName) {

		return ".do";
	}

	@SuppressWarnings({ "rawtypes", "unused" })
	public static void main(String[] args) {
		try {
			Class clazz = Class
					.forName("com.struts.business.action.UserAction");
			Field[] files = clazz.getFields();

			for (Field field : files) {

			}

		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}

	}
}
